package com.ysw.io.文件切分;


import com.ysw.io.数据分页.PartitionIndexInfo;
import com.ysw.io.数据分页.PartitionUtil;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.List;

/**
 * @author: yu_sw
 * @Description: com.ysw.io.文件切分
 * @date:2022/5/17 4:14
 */
public class FileSplitter {

    public static void main(String[] args) throws IOException {
        File file = new File("experience/src/main/java/com/ysw/io/data/data_01.txt");
        Long byteSize = file.length();
        RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
        List<PartitionIndexInfo> partition = partition(11, byteSize, randomAccessFile);
        String prefix = "experience/src/main/java/com/ysw/io/data/aaa";
        for (int i = 0; i < partition.size(); i++) {
            String fileName = prefix + "_" + i + ".txt";
            Long end = partition.get(i).getEnd();
            Long start = partition.get(i).getStart();
            splitBlock(start == 0 ? start : start - 1, end, randomAccessFile, fileName);
        }
        randomAccessFile.close();
    }

    /**
     * 文件生成
     *
     * @param start            开始索引位置
     * @param end              结束索引位置
     * @param sourceRandomFile 源文件
     * @param targetFileName   目标文件名称
     * @throws IOException
     */
    public static void splitBlock(long start, long end, RandomAccessFile sourceRandomFile, String targetFileName) {
        RandomAccessFile randomAccessFile = null;
        try {
            randomAccessFile = new RandomAccessFile(targetFileName, "rw");
            sourceRandomFile.seek(start);
            int readSize = (int) (end - start);
            byte[] flushBuffer = new byte[1024];
            int len;
            while ((len = sourceRandomFile.read(flushBuffer)) != -1) {
                if (readSize > len) {
                    randomAccessFile.write(flushBuffer, 0, len);
                    readSize -= len;
                } else {
                    randomAccessFile.write(flushBuffer, 0, readSize);
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                randomAccessFile.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 两个 for 循环完成对大文件的切分
     *
     * @param splitCount       需要切分的个数
     * @param totalSize        文件总长度
     * @param randomAccessFile 大文件访问类
     * @return
     * @throws IOException
     */
    public static List<PartitionIndexInfo> partition(int splitCount, long totalSize, RandomAccessFile randomAccessFile) throws IOException {
        if (splitCount < 2) {
            throw new IllegalArgumentException("切分块不能小于 2 ");
        }
        List<PartitionIndexInfo> partitionIndexInfos = PartitionUtil.partitionForPNum(totalSize, splitCount);
        //从第二个切分块开始，修正起、止位置：保证每块的终止位置处是\r\n 换行符
        long index = partitionIndexInfos.get(0).getEnd();
        for (int i = 1; i < splitCount; i++) {
            //定位到上一个切块的 end 处，往后寻找换行符号
            randomAccessFile.seek(index);
            byte oneByte = randomAccessFile.readByte();
            //判断是否是换行符号，如果不是换行符，那么读取到换行符为止
            while (oneByte != '\n' /*&& oneByte != '\r'*/) {
                randomAccessFile.seek(index++);
                oneByte = randomAccessFile.readByte();
            }
            // 结束时index位置\n
            PartitionIndexInfo previous = partitionIndexInfos.get(i - 1);
            PartitionIndexInfo current = partitionIndexInfos.get(i);
            previous.setEnd(index);
            current.setStart(index + 1);
            index = current.getEnd();
        }
        return partitionIndexInfos;
    }
}
